<?php
/**
 *
 * includes/mysql.class.php [last modified by xray]
 *
 * @package:	  expCounter
 * @version:	  1.2
 * @copyright:  since	2009 by Volker S. Latainski
 * @license:	  GPL 2.0 or higher(see docs/license.txt)
 * @link:       http://www.expblog.net/expcounter
 * @filesource
 *
 * based on chCounter 3.1.3 copyright by Christoph Bachner and Bert Koern (http://chcounter.org)
 *
 * *******************************************************************************************
 *
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program;
 * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
 * MA 02110, USA
 *
 * *******************************************************************************************
 */
class chC_mysql
{
  /**
   * The resultset
   * @var resource|bool
   */
  public $query_result;
  /**
   * Actual query string
   * @var string
   */
  public $statement;
  /**
   * Connection ID
   * @var int
   */
  public $connection_id;
  /**
   * Count of queries
   * @var int
   */
  public $queries = 0;
  /**
   * All errors as string
   * @var string
   */
  public $accepted_errors = '';
  /**
   * Stack for all statements of this connection
   * @var array
   */
  public $statements = array();
  /**
   * Debug mode
   * @var bool
   */
  public $debug = TRUE;
  /**
   * Die on error flag
   * @var bool
   */
  public $die_on_error = TRUE;
  /**
   * Error array
   * @var array
   */
  public $errors = array();
  /**
   * Array for table maintenance
   * @var array
   */
  public $repaired = array();
  /**
   * MySQL server
   * @var string
   */
  private $db_server;
  /**
   * MySQL username
   * @var string
   */
  private $db_user;
  /**
   * MySQL password
   * @var string
   */
  private $db_passwort;
  /**
   * MySQL database
   * @var string
   */
  private $db_database;

  /**
   * Constructor
   *
   * @param    string $db_server    Server Address
   * @param    string $db_user      Username
   * @param    string $db_passwort  Password
   * @param    string $db_database  Database
   * @param    string $debug        Debug Mode
   * @return   void
   * @access   public
   */
  public function __construct($db_server, $db_user, $db_passwort, $db_database = FALSE, $debug = '')
  {
    // debugging
    if($debug == 'DEBUG_OFF') $this->debug = FALSE;
    elseif($debug == 'DEBUG_ON') $this->debug = TRUE;

    // db data
    $this->db_server = $db_server;
    $this->db_user = $db_user;
    $this->db_passwort = $db_passwort;
    $this->db_database = $db_database;

    // new connection
    $this->connect();
  }

  /**
   * Connect to database
   *
   * @return   void
   * @access   private
   */
  private function connect()
  {
    $this->connection_id = @ mysql_connect($this->db_server, $this->db_user, $this->db_passwort) OR $this->_handle_error();

    // set charset to uft8
    if(version_compare(PHP_VERSION, '5.2.3', '>='))
    {
      @ mysql_set_charset('utf8');
    }
    else
    {
      @ mysql_query("SET NAMES 'utf8'");
    }

    if($this->db_database != FALSE)
    {
      @ mysql_select_db($this->db_database) OR $this->_handle_error();
    }
  }

  /**
   * Send statement/query
   *
   * @param    string $statement  SQL Query
   * @return   resource|bool
   * @access   public
   */
  public function query($statement)
  {
    $this->query_result = @mysql_query($statement, $this->connection_id);
    $this->queries++;
    if(mysql_errno())
    {
      if(mysql_errno() == 1016 || mysql_errno() == 1030)
      {
        $return = $this->_repair_table($statement);
        if($return == TRUE)
        {
          $this->query_result = @mysql_query($statement, $this->connection_id);
        }
        else
        {
          $this->_handle_error($statement);
        }
      }
      else
      {
        $this->_handle_error($statement);
      }
    }
    $this->statements[] = $statement;
    return $this->query_result;
  }

  /**
   * Error handling
   *
   * @param    string     $statement  SQL Query
   * @return   bool|exit
   * @access   private
   */
  private function _handle_error($statement = FALSE)
  {
    $this->errors[] = array(
        'statement' => $statement,
        'errno' => mysql_errno(),
        'error' => mysql_error()
    );

    if($this->debug == FALSE || (mysql_errno() != 0 && is_int(strpos($this->accepted_errors, (string) mysql_errno()))))
    {
      return FALSE;
    }

    if($this->debug == TRUE)
    {
      echo "<b>expCounter: MySQL error!</b><br />\n";
      if($statement != FALSE)
      {
        echo "SQL query:<br />\n"
        . "<ul style=\"margin-top:5px; margin-bottom:5px\">\n"
        . "<li><i>" . $statement . "</i></li>\n"
        . "</ul>\n<br />\n";
      }
      echo "Error number: " . mysql_errno() . "<br />\n" . mysql_error() . "\n";
      if($this->die_on_error == TRUE)
      {
        die("<br />\n<i>Script stopped.</i>");
      }
    }
    elseif($this->die_on_error == TRUE)
    {
      exit;
    }
  }

  /**
   * Table maintenance
   *
   * @param    string   $statement  SQL Query
   * @return   bool
   * @access   public
   */
  public function _repair_table($statement)
  {
    $tabellen = array(
        strtolower(CHC_TABLE_CONFIG),
        strtolower(CHC_TABLE_DATA),
        strtolower(CHC_TABLE_LOG_DATA),
        strtolower(CHC_TABLE_COUNTED_USERS),
        strtolower(CHC_TABLE_IGNORED_USERS),
        strtolower(CHC_TABLE_ONLINE_USERS),
        strtolower(CHC_TABLE_ACCESS),
        strtolower(CHC_TABLE_SCREEN_RESOLUTIONS),
        strtolower(CHC_TABLE_USER_AGENTS),
        strtolower(CHC_TABLE_SEARCH_ENGINES),
        strtolower(CHC_TABLE_REFERRERS),
        strtolower(CHC_TABLE_LOCALE_INFORMATION),
        strtolower(CHC_TABLE_PAGES),
        strtolower(CHC_TABLE_XSS_LOG)
    );
    if($count = preg_match_all('/(' . implode('|', $tabellen) . ')/i', $statement, $matches))
    {
      $nr = 0;
      for ($i = 0; $i < $count; $i++)
      {
        if(!isset($this->repaired[$matches[1][$i]]))
        {
          $this->query('REPAIR TABLE `' . $matches[1][$i] . '`;');
          $this->repaired[$matches[1][$i]] = TRUE;
          $nr++;
        }
      }
      if($nr > 0)
      {
        return TRUE;
      }
    }
    return FALSE;
  }

  /**
   * Set the debug mode
   *
   * @param    string   $mode  The Debug Mode
   * @return   void
   * @access   public
   */
  public function set_debug_mode($mode)
  {
    $this->debug = ($mode == 'DEBUG_OFF') ? FALSE : TRUE;
  }

  /**
   * Check if db connection is esteblished
   *
   * @return   bool
   * @access   public
   */
  public function is_connected()
  {
    if($this->connection_id == FALSE)
    {
      return FALSE;
    }
    else
    {
      return mysql_ping($this->connection_id);
    }
  }

  /**
   * Get error array
   *
   * @return   array
   * @access   public
   */
  public function get_errors()
  {
    return $this->errors;
  }

  /**
   * Reset error array
   *
   * @return   void
   * @access   public
   */
  public function reset_errors()
  {
    $this->errors = array();
  }

  /**
   * Set accepted errors
   *
   * @param    array   $errors  The Error Array
   * @return   void
   * @access   public
   */
  public function set_accepted_errors($errors)
  {
    $this->accepted_errors = (string) $errors;
  }

  /**
   * Protect the queries against SQL Injection
   *
   * @param    string   $string  SQL Query/Statement
   * @return   string
   * @access   public
   */
  public function real_escape_string($string)
  {
    return mysql_real_escape_string($string);
  }

  /**
   * Obsolet function! => linked to real_escape_string()
   *
   * @param    string   $string  SQL Query/Statement
   * @return   string
   * @access   public
   *
   * @todo remove from source code
   */
  public function escape_string($string)
  {
    return $this->real_escape_string($string);
  }

  /**
   * Fetch the result (row) as an associative array, a numeric array or both
   *
   * @param    resource   $query_result  The Resultset
   * @param    bool       $all           ---
   * @return   array
   * @access   public
   */
  public function fetch_array($query_result = FALSE, $all = FALSE)
  {
    return $this->_fetch('array', $query_result, $all);
  }

  /**
   * Fetch the result (row) as an associative array
   *
   * @param    resource   $query_result  The Resultset
   * @param    bool       $all           ---
   * @return   array
   * @access   public
   */
  public function fetch_assoc($query_result = FALSE, $all = FALSE)
  {
    return $this->_fetch('assoc', $query_result, $all);
  }

  /**
   * Fetch the result (row) as an enumerated array
   *
   * @param    resource   $query_result  The Resultset
   * @param    bool       $all           ---
   * @return   array
   * @access   public
   */
  public function fetch_row($query_result = FALSE, $all = FALSE)
  {
    return $this->_fetch('row', $query_result, $all);
  }

  /**
   * ---
   *
   * @param    ---        $type          ---
   * @param    resource   $query_result  The Resultset
   * @param    bool       $all           ---
   * @return   void
   * @access   public
   *
   * @todo eval is evil ;)
   */
  public function _fetch($type, $query_result, $all)
  {
    if($query_result == FALSE)
    {
      $query_result = $this->query_result;
    }

    if($all == FALSE)
    {
      return eval('return @mysql_fetch_' . $type . '( $query_result );');
    }
    else
    {
      $array = array();
      for ($i = 0; $i < @mysql_num_rows($query_result); $i++)
      {
        eval('$array[$i] = @mysql_fetch_' . $type . '( $query_result );');
      }
      return $array;
    }
  }

  /**
   * Get number of rows in $query_result
   *
   * @param    resource   $query_result  The Resultset
   * @return   int|NULL
   * @access   public
   */
  public function num_rows($query_result = FALSE)
  {
    return ($query_result != FALSE ) ? @mysql_num_rows($query_result) : @mysql_num_rows($this->query_result);
  }

  /**
   * Get the ID generated in the last query
   *
   * @return   int
   * @access   public
   */
  public function insert_id()
  {
    return @mysql_insert_id();
  }

  /**
   * Get number of affected rows in previous MySQL operation
   *
   * @return   int
   * @access   public
   */
  public function affected_rows()
  {
    return @mysql_affected_rows();
  }

  /**
   * Get number of queries
   *
   * @return   int
   * @access   public
   */
  public function get_number_of_queries()
  {
    return $this->queries;
  }

  /**
   * Get the last statement
   *
   * @return   string
   * @access   public
   *
   * @todo error handling
   */
  public function get_last_query()
  {
    return $this->statements[count($this->statements) - 1];
  }

  /**
   * Free all memory associated with the actual result
   *
   * @return   bool
   * @access   public
   */
  public function free_result()
  {
    @mysql_free_result($this->query_result);
  }

  /**
   * Close MySQL connection
   *
   * @return   bool
   * @access   public
   */
  public function close()
  {
    return @mysql_close($this->connection_id);
  }

  /**
   * Destructor
   *
   * @return   void
   * @access   public
   */
  public function __destruct() {}
}
?>